package com.sdjenkins.exercise.atm;


/**
 * This is the Model part of the Solution.
 * 
 * The one public method - processCommand. This will execute the command object passed to it
 * 
 * Where required, the customer balance is returned, or an error message.  
 *  
 * @author Simon Jenkins
 *
 */

public class ATMCommandProcessor {
	
	public enum Errors {ACCOUNT_ERR, FUNDS_ERR, ATM_ERR};
	public enum CommandType { withdraw, load, balance, validate, setBalance, reset }
	public static class Command {
		public Command(CommandType typ, String... pms) {
			type = typ;
			parms = pms;
		}
		public CommandType getType() {
			return type;
		}
		public String[] getParms() {
			return parms;
		}
		private CommandType type;
		private String[] parms;
	}

	private String accountInUse;
	private int accountBalance;
	private int accountOdLimit;
	private int cashRemining = 0;
	private boolean isAccountValid;
	
	
	public String processCommand(Command cmd) {
		String[] parms = cmd.getParms();
		switch (cmd.getType()) {
			case load : 		return doLoad(parms);
			case validate : 	return doValidate(parms);
			case setBalance : 	return doSetBalance(parms);
			case balance : 		return doGetBbalance();
			case withdraw : 	return doWithdraw(parms);
			case reset : 		return doReset();
		}
		return null;
	}

	private String doReset() {
		accountBalance = 0;
		accountInUse = null;
		accountOdLimit = 0;
		isAccountValid = false;
		return null;
	}

	private String doWithdraw(String[] parms) {
		String msg = hasFunds(parms[0]);
		if (msg == null) {
			msg = withdraw(parms[0]);
		}
		return msg;
	}
	private String withdraw(String required) {
		String msg = Errors.ACCOUNT_ERR+"";
		if (isAccountValid) {
			int req = toInt(required);
			accountBalance -= req;
			cashRemining -= req;
			msg = accountBalance+""; 
		}
		return msg;
	}

	private String hasFunds(String required) {
		String msg = null;
		int req = toInt(required);
		if (accountBalance+accountOdLimit < req) {
			msg= Errors.FUNDS_ERR+"";			
		}
		else if (cashRemining < req) {
			msg= Errors.ATM_ERR+"";
		}
		return msg;
	}

	private String doGetBbalance() {
		String msg = Errors.ACCOUNT_ERR+"";
		if (isAccountValid) {
			msg = accountBalance+""; 
		}
		return msg;		
	}
	
	private String doSetBalance(String[] parms) {
		String msg = Errors.ACCOUNT_ERR+"";
		if (accountInUse != null) {
			accountBalance = toInt(parms[0]);
			accountOdLimit = toInt(parms[1]);
			isAccountValid = true;
			msg = null;
		}
		return msg;
	}
	private String doValidate(String[] parms) {
		String msg = Errors.ACCOUNT_ERR+"";
		if (toInt(parms[1]) == toInt(parms[2])) {
			accountInUse = parms[0];
			msg = null;
		}
		return msg;
	}
	private String doLoad(String[] parms) {
		cashRemining += toInt(parms[0]);
		return null;
	}

	private int toInt(String val){
		int i = 0;
		try {
			i = Integer.parseInt(val);
		}
		catch (Exception e) {
			throw new RuntimeException("Excepted integer value from Command", e);
		}
		return i;
	}
}

